/**
 * 20210823：创建，原THREE.Face3被移除
 * 20211116：新增包围球相关代码
 * 20221018: restructuring with typescript, major alteration.
 */
 import {Vector3,Sphere, Matrix4} from "three";
import { Loose, TypedArray } from "three-lib/general/utils";

 /**
  * 数学三点面
  */
 export default class Face3{

    private _a:Vector3;
    private _b:Vector3;
    private _c:Vector3;
    private _n:Vector3;
    private _tV0:Vector3;
    private _tV1:Vector3;
    private _needsUpdate:boolean;
    private _sphere:Sphere;
    private _userData:Loose<any>;

     constructor(a?:Vector3,b?:Vector3,c?:Vector3){
         this._a=a?a.clone():new Vector3();
         this._b=b?b.clone():new Vector3();
         this._c=c?c.clone():new Vector3();
         this._n=new Vector3();
         this._tV0=new Vector3();
         this._tV1=new Vector3();
         this._needsUpdate=true;
         this._sphere=new Sphere();
         this._userData={};
     }
 
     public get a():Vector3{
         return this._a;
     }
     public set a(vec3:Vector3){
         this._needsUpdate=true;
         this._a.copy(vec3);
     }
 
     public get b():Vector3{
         return this._b;
     }
     public set b(vec3:Vector3){
         this._needsUpdate=true;
         this._b.copy(vec3);
     }
 
     public get c():Vector3{
         return this._c;
     }
     public set c(vec3:Vector3){
         this._needsUpdate=true;
         this._c.copy(vec3);
     }
 
     public get normal():Vector3{
         if(this._needsUpdate)this.update();
         return this._n;
     }
 
     /**
      * bound sphere
      */
     public get sphere():Sphere{
         if(this._needsUpdate)this.update();
         return this._sphere;
     }
 
     /**
      * user data object
      */
     public get userData():Loose<any>{
         return this._userData;
     }
 
     /**
      * Set a vertex of a face using vertex index and x,y,z
      */
     public setByValue(component:0|1|2|'a'|'b'|'c',x:number,y:number,z:number):this{
         this._needsUpdate=true;
         switch (component) {
             case 0:
                 this._a.set(x,y,z);
                 break;
             case 1:
                 this._b.set(x,y,z);
                 break;
             case 2:
                 this._c.set(x,y,z);
                 break;
             case 'a':
                 this._a.set(x,y,z);
                 break;
             case 'b':
                 this._b.set(x,y,z);
                 break;
             case 'c':
                 this._c.set(x,y,z);
                 break;
         }
         return this;
     }
 
     /**
      * Set a vertex of a face using vertex index and corresponding (typed) array
      */
     public setByIndex(component:0|1|2|'a'|'b'|'c',index:number,array:TypedArray|Array<number>):this{
         this._needsUpdate=true;
         let i=index*3;
         switch (component) {
             case 0:
                 this._a.set(array[i],array[i+1],array[i+2]);
                 break;
             case 1:
                 this._b.set(array[i],array[i+1],array[i+2]);
                 break;
             case 2:
                 this._c.set(array[i],array[i+1],array[i+2]);
                 break;
             case 'a':
                 this._a.set(array[i],array[i+1],array[i+2]);
                 break;
             case 'b':
                 this._b.set(array[i],array[i+1],array[i+2]);
                 break;
             case 'c':
                 this._c.set(array[i],array[i+1],array[i+2]);
                 break;
         }
         return this;
     }
 
     public applyMatrix4(mat4:Matrix4):this{
         this._a.applyMatrix4(mat4);
         this._b.applyMatrix4(mat4);
         this._c.applyMatrix4(mat4);
         this._needsUpdate=true;
         return this;
     }
 
     /**
      * update normal
      */
     public update():void{
         this._tV0.subVectors(this._b,this._a);
         this._tV1.subVectors(this._c,this._a);
         this._n.crossVectors(this._tV0,this._tV1).normalize();
         this._sphere.setFromPoints([this._a,this._b,this._c]);
         this._needsUpdate=false;
     }
 
     public copy(face:Face3):this{
         this._a.copy(face.a);
         this._b.copy(face.b);
         this._c.copy(face.c);
         this._n.copy(face.normal);
         this._needsUpdate=face._needsUpdate;
         return this;
     }
 
     public clone():Face3{
         let c=new Face3();
         c.copy(this);
         return c;
     }
 }